Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Ruby and Python

7 views
Skip to first unread message

June Kim

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
I've read some comparisons between Ruby and Python from Ruby-centric view.
They estimate that four years will see Ruby overtake Python.

Has anyone used Ruby here? or are there some documents at least unbiased --
yet, Python-centric view would be okay if not too fictional.

Best regards,

June


Peter Hansen

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
June Kim wrote:
>
> I've read some comparisons between Ruby and Python from Ruby-centric view.
> They estimate that four years will see Ruby overtake Python.

"Four years"? In the computer industry, and in terms of "Internet
time", that's so far beyond anyone's ability to predict that it's an
irrelevant claim. Java was announced only five years ago and look where
it is compared to all the claims made in the early days (although it's
stood up remarkably well).

> Has anyone used Ruby here? or are there some documents at least unbiased --
> yet, Python-centric view would be okay if not too fictional.

There are some unbiased views out there, if you just search (Try
http://www.google.com/search?q=python+ruby+comparison for example).

I would judge it extremely unlikely that anything will "unseat" Python
in the minds, hearts, and companies of many people for quite some time.
That's because it is extremely effective, easy to learn and maintain,
fun, powerful, flexible, and integrates so many different things
together that it's not even funny.

If you have practical reasons for needing Ruby (small memory space?) it
would doubtless be a very good solution for you. If you have no
specific driving need for what Ruby gives you that Python does not,
Python will, IMHO, be a far more suitable option.

--
Peter Hansen

Aahz Maruch

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
In article <8v0nr4$i32$1...@news.nuri.net>,

June Kim <junaf...@nospamplzyahoo.com> wrote:
>
>I've read some comparisons between Ruby and Python from Ruby-centric view.
>They estimate that four years will see Ruby overtake Python.

Haven't used Ruby, but IIRC, it's only available for Windoze. From that
standpoint alone, no way will Ruby overtake Python.
--
--- Aahz (Copyright 2000 by aa...@pobox.com)

Androgynous poly kinky vanilla queer het <*> http://www.rahul.net/aahz/
Hugs and backrubs -- I break Rule 6

"...thinks that usenet is weird in that with a click of a mouse you
could be a global fool/troll/idiot within a minisecond and not even
realise it." --janma

Lyle Johnson

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
> Haven't used Ruby, but IIRC, it's only available for Windoze. From that
> standpoint alone, no way will Ruby overtake Python.

Bonk! Wrong answer. To quote the FAQ, it is developed under Linux but runs
under Unix, DOS, Windows, MacOS, BeOS, Amiga, Acorn Risc OS (???) and OS/2.

I've just started looking at Ruby, mainly because my curiosity got the
better of me. So far I'm underwhelmed. I can see how it might appeal to Perl
users but not Python users. I'll try to present my finding to the newsgroup
after I've had more time to give it a fair shake.


Just van Rossum

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
Lyle Johnson wrote:
> I've just started looking at Ruby, mainly because my curiosity got the
> better of me. So far I'm underwhelmed. I can see how it might appeal to Perl
> users but not Python users. I'll try to present my finding to the newsgroup
> after I've had more time to give it a fair shake.

One odd thing I came across: while in Ruby apparently everything is an
instance (no difference between types and classes) I read somewhere that
functions and methods are _not_ first class citizens.

Just

Aahz Maruch

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
In article <t180er4...@corp.supernews.com>,
Lyle Johnson <ljoh...@resgen.com> wrote:
>attribution for Aahz restored:

>>
>> Haven't used Ruby, but IIRC, it's only available for Windoze. From that
>> standpoint alone, no way will Ruby overtake Python.
>
>Bonk! Wrong answer. To quote the FAQ, it is developed under Linux but runs
>under Unix, DOS, Windows, MacOS, BeOS, Amiga, Acorn Risc OS (???) and OS/2.

Sorry, brain fart.

Alex Martelli

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
"June Kim" <junaf...@nospamplzyahoo.com> wrote in message
news:8v0t8l$m4b$1...@news.nuri.net...
[snip]
> So, may I ask you what you think are the strong points or specific usages
> for Ruby when compared with Python? I'd really appreciate it.

I can't talk to the specific implementations (which are changing
all the time anyway) -- if you have specific needs, benchmarking
both languages' current implementations in conditions approximating
those you'll be using may be the only way to go. E.g., if you
want your program to run on a JVM, or on MS .NET, get Jython or
Python .NET, the equivalent Ruby implementations (if any -- if
no such implementations exist, Ruby's ruled out), and try.

E.g., Ruby is said to be faster and consume less memory (I have
not done any measurement myself, please note!); if this is
confirmed in your application-specific benchmarks, and the
performance-difference is crucial to your application, that
could be the clincher (unless and until the Python team chooses
to devote some more implementation effort to performance
issues and possibly get back to parity, of course:-).


As languages, they're pretty close. Ruby has the Smalltalk-ish
features that: you can inherit from anything, fixnums and
bignums mutate invisibly into each other (most love this, some
hate this), that inheritance is single (most will hate this,
some will love it), that you 'send a block of code to a method' --
but the difference here is really not much more than syntax sugar,
Ruby's
array.each{|item| print item, "\n"}
vs Python's
for item in array: print item
or Ruby's
array.sort{|a,b| a <=> b}
vs Python's
array.sort(lambda a, b: cmp(a,b))
etc etc. Python sometimes needs you to give a name to a local
function rather than pass an anonymous codeblock, and make a
closure by explicit binding of 'defaulted-arguments' -- minor
things; vice versa, I hear that functions, classes, bound and
unbound methods, etc, aren't first-class objects in Ruby -- I'm
not sure what this implies, but it makes me edgy:-).

The approach to syntax sugar is rather different -- Python is
heavily 'minimalistic', Ruby much less so (@var and $var stropping
for scoping, explicit {/} bracketing, explicit 'end' keyword).

Some Ruby features still listed as "advantages over Python" in
articles you find around aren't so any more -- e.g., "Python
has no real garbage collection" (it now does), "no methods on
strings" (now there are).


But I think the summary bottom-line can fairly be given in
the words of Yukihiro Matsumoto, Ruby's author: "Ruby is
hovering near the edge of too complicated".

All programming environments tend to grow with time, to
become richer and more complex. If an environment is
"near the edge of too complicated" NOW, where will it be
in 4 years? Python is still a safe distance from that
edge -- and if we, collectively, remember that its
simplicity *IS* its strength, we can keep it on the
right side of the edge indefinitely... if so, then count
me in FIRMLY in Python's camp for good. "Do the simplest
thing that could possibly work" is the Golden Rule I try
to live by...!-)


Alex


Robert L Hicks

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
The FAQ may say that...but there are no binary distros like python has at
the moment. I run on the MacOS and could not find the version for Mac on the
Ruby site. There is only *nix and Windows binaries. Another bad point is I
believe you have to have something like cygwin to run it on Windows.

I agree with your point on being underwhelmed. I find Python (even with its
whitespace) much easier to read.

Will it *overtake* python? I doubt it, but I do not predict the future.
Python is much more mature and I have faith in its maintainers to continue
doing the outstanding job of refining the rough edges.

Robert

> From: "Lyle Johnson" <ljoh...@resgen.com>
> Organization: Research Genetics, Inc.
> Newsgroups: comp.lang.python
> Date: Thu, 16 Nov 2000 09:51:42 -0600
> Subject: Re: Ruby and Python
>
>> Haven't used Ruby, but IIRC, it's only available for Windoze. From that
>> standpoint alone, no way will Ruby overtake Python.
>
> Bonk! Wrong answer. To quote the FAQ, it is developed under Linux but runs
> under Unix, DOS, Windows, MacOS, BeOS, Amiga, Acorn Risc OS (???) and OS/2.
>

Johann Hibschman

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
Just van Rossum writes:

> Lyle Johnson wrote:
>> I've just started looking at Ruby, mainly because my curiosity got the
>> better of me. So far I'm underwhelmed. I can see how it might appeal to Perl
>> users but not Python users. I'll try to present my finding to the newsgroup
>> after I've had more time to give it a fair shake.

> One odd thing I came across: while in Ruby apparently everything is an


> instance (no difference between types and classes) I read somewhere that
> functions and methods are _not_ first class citizens.

I've been playing with Ruby off and on for a few weeks. It's a nice
language, with a few nice features, but it's not quite compelling
enough to make me switch.

First, functions and methods are not first class. In practice, it's not
a problem. It's easy to bind an object and method into a single callable
object and then pass that object around. Invoking it just doesn't look
exactly like a traditional function/method call.

If object "cat" has a method "meow", you can bind that up into an object
by calling

f = cat.method(:meow)
f.call() # calls cat.meow()

The principle is that you have to make a callable object, if you want
something to pass around. I don't know about classes yet.

Ruby does have a few big wins. The syntax sugar for blocks is *much*
nicer than the Python lambda expressions. Blocks are lexically
scoped, so you don't have Python's somewhat arbitrary and complicated
scoping rules. Iterators are wonderful; python could get them with
Stackless, but it would take some work.

While playing around with Ruby, I came up with the following simple
class to learn iterators

# set of Die's
class Dice
def initialize(*dice)
@dice = dice
end

def dice_combs(dice)
if dice.length == 1
1.upto(dice[0]) {|n| yield([n])}
else
1.upto(dice[0]) {|n|
dice_combs(dice[1...dice.length]) {|ns|
yield([n]+ns)
}
}
end
end
private :dice_combs

# run through all permutations
def each
dice_combs(@dice) {|v| yield(v)}
end

attr :dice
end

which lets you iterate over all possible combinations via

ds = Dice.new 2, 2, 2
ds.each {|a, b, c| print a, " ", b, " ", c, "\n"}
1 1 1
1 1 2
1 2 1
1 2 2
2 1 1
2 1 2
2 2 1
2 2 2

I thought that was pretty neat. It's not all that far from Stackless
to good python iterators, although the lack of a corresponding block
structure in Python makes it hard.

--
Johann Hibschman joh...@physics.berkeley.edu

Quinn Dunkan

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
On Fri, 17 Nov 2000 00:07:30 +0900, June Kim <junaf...@nospamplzyahoo.com>
wrote:

>So, may I ask you what you think are the strong points or specific usages
>for Ruby
>when compared with Python? I'd really appreciate it.

I've used ruby a bit, and while it's a nice language, it won't be overtaking
my heart or mind any time soon. Its pros have been well discussed, but I find
some significant cons: it's much more complicated than python. It inherits
many operators with different preceedences (and vs. &&) from perl and C. It
has *two* kinds of exceptions (begin, ensure, vs. try catch throw). Variable
names are different if they begin with a capital letter, lowercase letter, or
@ sign. I find the syntax too complicated to understand easily (associativity
of begin .. end constructs vs {} constructs, ambiguity of method calls without
parens, etc.). Do you want your class to inherit from another class? Extend
it? Include it? They all do different things (ironically, I never really
understood the difference until I learned sather, where it suddenly made
sense, but sather enforces the difference between code-inclusion and
subtyping, where ruby doesn't). It's got perl-style $$ $_ etc. variables,
although you can avoid them more easily. Do you want to define a singleton
method? A singleton class? With private attributes? Public attbributes?
Since methods are not first class there a whole other set of keywords for
doing the same thing for methods. And don't forget about :symbols and
iterators (another thing that made much more sense to me in sather, but maybe
that's just me).

These are mostly nice features, to be sure, but they're also just that:
features. C++ has features. Python doesn't have a stellar score on my
elegance-o-meter, but for me its major win is the lack of features, and lack
of ambiguities. It fits in my brain.

I'll probably use ruby more in the future, just for fun. I think everyone who
likes dynamic languages like python and scheme should take a look at it, and
see if they like it. But I write in a lot of languages for fun, and ruby
doesn't stand out as something that grabs me by the throat with it's power and
practicality like python does :)

Peter Hansen

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
June Kim wrote:

>
> "Peter Hansen" <pe...@engcorp.com> wrote:
> > There are some unbiased views out there, if you just search (Try
> > http://www.google.com/search?q=python+ruby+comparison for example).
> >
> > If you have practical reasons for needing Ruby (small memory space?) it
> > would doubtless be a very good solution for you. If you have no
> > specific driving need for what Ruby gives you that Python does not,
> > Python will, IMHO, be a far more suitable option.
>
> So, may I ask you what you think are the strong points or specific usages
> for Ruby when compared with Python? I'd really appreciate it.

No, sorry, I have not used Ruby or looked at it beyond a quick bit of
research on the web, which I still urge you to undertake, starting with,
perhaps, the link I included above. I easily and quickly found enough
information to let me eliminate the language from any serious
consideration for my purposes. (One of the things I found was the
relative popularity of Python, the other was the relative
unmaintainability of Ruby, since it follows the C-inspired tradition of
punctuation-laden syntax. Those two things certainly played a major
role in my quick dismissal of it.)

As I tried to hint with "if you have practical reasons for needing
Ruby", what matters more than some arbitrary list of features on which I
or someone else might focus is *your* needs. What role will the
language you seek play for you? Are you looking at embedded systems,
systems programming, a hobby, artificial intelligence explorations,
machine control, database work, GUI applications, or what? If you have
a specific need, those of us who are very familiar with Python's
suitability in that area would be happy to help. If you have no idea
what you really need, there is really no question for us to answer...

--
Peter Hansen

Grant Griffin

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to
June Kim wrote:
>
> I've read some comparisons between Ruby and Python from Ruby-centric view.
> They estimate that four years will see Ruby overtake Python.
>
> Has anyone used Ruby here? or are there some documents at least unbiased --
> yet, Python-centric view would be okay if not too fictional.

Not knowing anything about Ruby beyond what I've read in a couple of
online articles, it sounds like it's competition for Perl more than
Python. Specifically, it seems to be pretty Perlish, except that it
seems to have cured some of Perl's flaws; from what I read, it seems to
be "a better Perl". (Those who design a "new" programming language
don't have to perpetually repeat the lessons of history for the sake of
backwards compatability. <wink>)

But while I was reading about Ruby, one thing stood out. Ruby's creator
said something to the effect that he didn't like Python's use of
indentation to denote blocks. True, that's a relatively rare feature in
the pantheon programming languages, and perhaps in the big scheme of
things it's not something every language oughtta have. But the true
Pythoneer understands why Python does that, and he loves Python for it.
So while I can't predict which languages the masses will prefer in the
future, I think it's fair to say that Pythoneers, at least, are likely
to continue to prefer Python to a language designed by someone who
(frankly) "just doesn't get it"*.

besides,-"a-better-perl"-is-an-oxymoron-<wink>-ly y'rs,

=g2
*see http://www.python.org/doc/Humor.html#zen. For those of us whose
approach to programming adheres to these principle, no programming
language known to Man allows us to express ourselves better than Python.
--
_____________________________________________________________________

Grant R. Griffin g...@dspguru.com
Publisher of dspGuru http://www.dspguru.com
Iowegian International Corporation http://www.iowegian.com

June Kim

unread,
Nov 16, 2000, 10:07:30 AM11/16/00
to

"Peter Hansen" <pe...@engcorp.com> wrote in message
news:3A13F552...@engcorp.com...

> June Kim wrote:
> >
> > I've read some comparisons between Ruby and Python from Ruby-centric
view.
> > They estimate that four years will see Ruby overtake Python.
>
> "Four years"? In the computer industry, and in terms of "Internet
> time", that's so far beyond anyone's ability to predict that it's an
> irrelevant claim. Java was announced only five years ago and look where
> it is compared to all the claims made in the early days (although it's
> stood up remarkably well).
>
> > Has anyone used Ruby here? or are there some documents at least
unbiased --
> > yet, Python-centric view would be okay if not too fictional.
>
> There are some unbiased views out there, if you just search (Try
> http://www.google.com/search?q=python+ruby+comparison for example).
>
> I would judge it extremely unlikely that anything will "unseat" Python
> in the minds, hearts, and companies of many people for quite some time.
> That's because it is extremely effective, easy to learn and maintain,
> fun, powerful, flexible, and integrates so many different things
> together that it's not even funny.
>
> If you have practical reasons for needing Ruby (small memory space?) it
> would doubtless be a very good solution for you. If you have no
> specific driving need for what Ruby gives you that Python does not,
> Python will, IMHO, be a far more suitable option.
>

So, may I ask you what you think are the strong points or specific usages
for Ruby
when compared with Python? I'd really appreciate it.

Best regards,

June


June Kim

unread,
Nov 16, 2000, 11:08:53 AM11/16/00
to

"Lyle Johnson" <ljoh...@resgen.com> wrote in message
news:t180er4...@corp.supernews.com...

> > Haven't used Ruby, but IIRC, it's only available for Windoze. From that
> > standpoint alone, no way will Ruby overtake Python.
>
> Bonk! Wrong answer. To quote the FAQ, it is developed under Linux but runs
> under Unix, DOS, Windows, MacOS, BeOS, Amiga, Acorn Risc OS (???) and
OS/2.
>
> I've just started looking at Ruby, mainly because my curiosity got the
> better of me. So far I'm underwhelmed. I can see how it might appeal to
Perl
> users but not Python users. I'll try to present my finding to the
newsgroup
> after I've had more time to give it a fair shake.
>

One interesting thing is that the Ruby miner or creator himself was an early
dawn-breaker in Python and recognized some shortcomings -- in his way -- and
tried to excel Python and other half-blooded OOPLs. In a recent interview
with the authors of Programming Ruby, on Amazon site, they said Ruby's speed
is somewhere between Python and Perl.


Gareth McCaughan

unread,
Nov 16, 2000, 7:02:05 PM11/16/00
to
Lyle Johnson wrote:

> Bonk! Wrong answer. To quote the FAQ, it is developed under Linux but runs
> under Unix, DOS, Windows, MacOS, BeOS, Amiga, Acorn Risc OS (???) and OS/2.

"Acorn RISC OS" is the operating system used by a range of
ARM-based desktop machines made by Acorn Computers Ltd (who
no longer exist, having been bought). The ARM processor
was developed by Acorn (the "A" in the name originally
stood for "Acorn", not "Advanced"), and when it first
appeared it was terribly impressive.

RISC OS is a rather quirky operating system-cum-GUI. The
OS itself has some neat features but is on the whole
pretty lame. The GUI is excellent. There are some
startlingly good applications. Be all that as it may,
the platform is clearly doomed. It's been a tiny minority
for ages, except in schools in the UK (where it's fast
disappearing now).

--
Gareth McCaughan Gareth.M...@pobox.com
sig under construc

John Dell'Aquila

unread,
Nov 17, 2000, 1:26:31 AM11/17/00
to
June Kim wrote:
> Has anyone used Ruby here? or are there some documents at least
unbiased --
> yet, Python-centric view would be okay if not too fictional.

Ruby is Smalltalk with Perlish syntax.
Python is ... (this is c.l.p., you fill in the blank)

Python and Ruby are both object oriented languages that provide a
smooth transition from procedural to OO programming styles. Smalltalk,
by contrast, is object only - you can't do anything until you understand
objects, inheritance and the sizable Smalltalk class hierarchy. By
providing procedural training wheels, Python and Ruby "fix" one of
the features that may have kept Smalltalk out of the mainstream.
The two languages differ by approaching this solution from
opposite directions.

Python is a hybrid language. It has functions for procedural
programming and objects for OO programming. Python bridges
the two worlds by allowing functions and methods to interconvert
using the explicit "self" parameter of every method def. When a
function is inserted into an object, the first argument automagically
becomes a reference to the receiver.

Ruby is a pure OO language that can masquerade as a procedural one.
It has no functions, only method calls. In a Ruby method the receiver,
also called self, is a hidden argument like "this" in C++. A "def"
statement outside of a class definition, which is a function in
Python, is actually a method call in Ruby. These ersatz functions
become private methods of class Object, the root of the Ruby class
hierarchy. Procedural programming is neatly solved from the other
direction - everything is an object. If the user doesn't grok objects
yet, they can just pretend that "def" is a function definition and
still get useful work done.

Ruby's OO purity provides a number features that Python lacks or is
still workng toward: a unified type / class hierarchy, metaclasses,
the ability to subclass *everything*, and uniform method invocation
(none of this len() is a function but items() is a method rubbish).
Ruby, like Smalltalk, only supports single inheritance, but it does
have a very powerful mixin concept: a class definition may
include a module, which inserts that module's methods, constants,
etc. into the class.

Ruby, again like Smalltalk, provides closures and code blocks and uses
them to the same good effect. The Ruby collection classes and
iterators are outstanding, much more powerful and elegant than the ad
hoc solutions that Python is sprouting (lambdas and list comprehensions).

Ruby's syntax and design philosophy are heavily influenced by Perl. It
has a lot of syntactic variability. Statement modifiers (if, unless,
while, until, etc.) may appear at the end of any statement. Some key
words are optional (the "then" in an "if" statement for example).
Parentheses may sometimes be elided in method calls. The
receiver of a method may usually be elided. Many, many things are
lifted directly from Perl. Built in regular expressions, $_ and
friends, here documents, the single-quoted / double-quoted string
distinction, $ and @ prefixes to distinguish different kinds of names
and so forth.

If you like Perl, you will like Ruby and be right at home with its
syntax. If you like Smalltalk, you will like Ruby and be right at home
with its semantics. If you like Python, you may or may not be put off
by the huge difference in design philosophy between Python and
Ruby/Perl.

Ruby is much more complex than Python but its features, for
the most part, hang together well. Ruby is well designed and full
of neat ideas that might be mined for P3K. I'm not sure how many
Python programmers will be attracted to it though - it hasn't won me
over (yet). But it is worthy of serious study and could be a real threat
to Perl.

John Dell'Aquila


Alex Martelli

unread,
Nov 17, 2000, 3:00:00 AM11/17/00
to
"Peter Hansen" <pe...@engcorp.com> wrote in message
news:3A14B8A1...@engcorp.com...
[snip]

> machine control, database work, GUI applications, or what? If you have
> a specific need, those of us who are very familiar with Python's
> suitability in that area would be happy to help. If you have no idea
> what you really need, there is really no question for us to answer...

One Lewis Carroll commented on this very issue some while ago...:

"""
`Would you tell me, please, which way I ought to go from here?'

`That depends a good deal on where you want to get to,' said the Cat.

`I don't much care where--' said Alice.

`Then it doesn't matter which way you go,' said the Cat.

`--so long as I get SOMEWHERE,' Alice added as an explanation.

`Oh, you're sure to do that,' said the Cat, `if you only walk long
enough.'
"""


Alex


Alex Martelli

unread,
Nov 17, 2000, 3:00:00 AM11/17/00
to
"Johann Hibschman" <joh...@physics.berkeley.edu> wrote in message
news:mt66lnh...@astron.berkeley.edu...
[snip]

Generators (and perhaps, more generally, coroutines) are indeed a
great thing, and I can't wait for Python to get them!-), but this
specific task easily admits of a differently-structured solution
(thanks to the fact that you may see "the N-th combination" as
a sequence of based-digits, with each digit-position having a
distinct base -- the bases are just the 'self.dice' or @dice...).

E.g.:
class Dice:
def __init__(self, *dice):
self.dice = list(dice)
self.dice.reverse()
def __getitem__(self, n):
result = []
for die in self.dice:
n,this = divmod(n,die)
result.append(1+this)
if n: raise IndexError
result.reverse()
return result

(I don't know how to express the for...append loop as a
Python 2 list-comprehension -- funny, maybe I'm just having
a brainstorm -- I usually find list comprehensions neater
and handier than such for...append loops, but here I just
cant' seem to do it...?)

Anyway, even without the list-comprehension this seems to
me to be more concise and transparent than the Ruby version.
The 'iterator' just becomes 'give me the n-th item in the
sequence, please raise IndexError if there IS no n-th item'.

Not *every* generator maps to this Python idiom, but lots
do -- and even many more, with a simple mixin such as:

class IteratorOnly:
def __init__(self, next, rewind):
self.__next=next
self.__rewind=rewind
self.__nextindex=None
def __getitem__(self, n):
if n==0:
self.__rewind()
self.__nextindex=0
if n!=self.__nextindex:
raise ValueError, "Only for-loop supported"
self.__nextindex += 1
return self.__next()

This lets any class follow the iterator-protocol needed
by the for-loop if: it doesn't know how to compute its
"n-th item", but does have methods for "next-item" and
"rewind", with 'next-item' returning IndexError if
there IS no next-item.

If I didn't know about base-digits, for example, I
might implement Dice this way...:

class Dice(IteratorOnly):
def __init__(self, *dice):
self.dice = list(dice)
IteratorOnly.__init__(self, self._next, self._rewind)
def _rewind(self):
self.state = [1] * len(self.dice)
self.state[-1] = 0
def _next(self):
for i in range(len(self.dice)):
j = -i-1
self.state[j] += 1
if self.state[j] <= self.dice[j]:
return self.state
else: self.state[j] = 1
else: raise IndexError

Not quite as concise and transparent as the special
solution above, but still pretty workable, and based
on the simple and often-applicable paradigm of "get
next state if any given current one / reset state at
sequence-start" (the mixin-class is written once,
then forgotten, of course...:-).

Sometimes you get intrinsically-recursive problems
for which no such linearized iteration paradigm is
a good, simple fit (e.g., 'fringe of a tree' -- you
need to either use recursion or simulate it with
your own stack for that...) -- and these are the
cases where one really hungers for generators. But
in my experience they don't tend to be all that
many as one might think.


So, anyway, however you implement class Dice (say
in module dice), the client-code is always:

>>> ds = dice.Dice(2,2,2)
>>> for a,b,c in ds:
print a,b,c

and, I may be biased, of course, but it does seem to
me to be quite simpler and clearer than the given
Ruby equivalent, i.e.:

ds = Dice.new 2, 2, 2
ds.each {|a, b, c| print a, " ", b, " ", c, "\n"}


If/when Python DOES finally get generators, I hope
they'll be made accessible through the simple "for-
loop protocol" (perhaps needing a simple mixin for
wrapping them to the suitable form... that would
not be a big problem!).


And, one more thing... suppose than, rather than
REALLY needing to enumerate all items of an object,
what we really want to know is whether this sequence
contains a certain 'target', e.g.:

for combo in ds:
if combo==mycombo:
print "yes!"
break
else:
print "no..."

(Presumably there is some way to code the equivalent
in Ruby, passing to ds.each a block which does a test
and breaks the iteration if the test succeeds...?)

Well, Python *wraps this very common idiom for us*!
Since ds satisfies the 'for-loop protocol', then
the existence of a given 'target' in the sequence
of its sub-items can ALSO be tested by coding:

if mycombo in ds: print "yes!"
else: print "no..."

which internally, by default, expands to the same
thing as the above-exemplified loop. *Further*,
if we decide this is a frequent operation and want
to optimize it, *with no change in client-code*,
we just need to add to class Dice one method...:

def __contains__(self, item):
if type(item) != type([]): return 0
if len(item)!=len(self.dice): return 0
for i in range(len(item)):
if item[i]<=0 or item[i]>self.dice[-i-1]:
return 0
return 1

in the former version, where self.dice is kept
in reversed form for convenience in iteration;
in the latter version, e.g., the niftier:

def __contains__(self, item):
if type(item) != type([]): return 0
if len(item)!=len(self.dice): return 0
for this, die in zip(item,self.dice):
if not 0<this<=die: return 0
return 1

thus turning the containment-test (again, with
NO change to client-code!) from O(N!) down to
O(N)... dunno 'bout YOU, but good old me IS
impressed by this kind of little speedups!-)


Alex


Steve Williams

unread,
Nov 17, 2000, 7:00:54 PM11/17/00
to
Quinn Dunkan wrote:

> [snip]

> These are mostly nice features, to be sure, but they're also just that:
> features. C++ has features. Python doesn't have a stellar score on my
> elegance-o-meter, but for me its major win is the lack of features, and lack
> of ambiguities. It fits in my brain.

[snip]

Easily the most profound, personally satisfying comment about computer languages
and systems I have read in a long, long time.

Utility, Firmness, Delight


Alex Martelli

unread,
Nov 17, 2000, 6:39:42 PM11/17/00
to
"Alex Martelli" <ale...@yahoo.com> wrote in message
news:8v37c...@news2.newsguy.com...
[snip]

> if mycombo in ds: print "yes!"
> else: print "no..."
[snip]

> def __contains__(self, item):
> if type(item) != type([]): return 0
> if len(item)!=len(self.dice): return 0
> for i in range(len(item)):
> if item[i]<=0 or item[i]>self.dice[-i-1]:
> return 0
> return 1

Silly me -- I need to add a guard against non-integer
elements in the 'item' list. E.g.:

def __contains__(self, item):
if type(item) != type([]): return 0
if len(item)!=len(self.dice): return 0
for i in range(len(item)):

if item[i] != int(item[i]): return 0


if item[i]<=0 or item[i]>self.dice[-i-1]:
return 0
return 1


Alex

Raffael Cavallaro

unread,
Nov 18, 2000, 1:08:33 AM11/18/00
to
In article <B63994CA.5E9F%bobh...@adelphia.net>, Robert L Hicks
<bobh...@adelphia.net> wrote:

>I run on the MacOS and could not find the version for Mac on the
>Ruby site.

< http://www.imasy.or.jp/~hisa/ruby/files/macruby-11b7-010d0.sit.bin>

I found it via Google. However, the docs are all in Japanese, and it's
pretty unstable (double clicking a compiled script crashed the Finder).

It makes Mac Python look rock solid, and that's saying a lot.

Raf

--

Raffael Cavallaro, Ph.D.
raf...@mediaone.net

graham

unread,
Nov 18, 2000, 3:00:00 AM11/18/00
to
Johann Hibschman

> I've been playing with Ruby off and on for a few weeks. It's a nice
> language, with a few nice features, but it's not quite compelling
> enough to make me switch.
>
> First, functions and methods are not first class. In practice, it's not
> a problem. It's easy to bind an object and method into a single callable
> object and then pass that object around. Invoking it just doesn't look
> exactly like a traditional function/method call.

But functions in Python aren't first class either. The most obvious evidence
of this is having to write manual closures. How does this differ from
wrapping a function in a callable object (which you can do in Python too).

graham


graham

unread,
Nov 18, 2000, 3:00:00 AM11/18/00
to
Alex Martelli
> "graham" <grah...@telocity.com> wrote in message

>> But functions in Python aren't first class either. The most obvious
>> evidence of this is having to write manual closures.
>
> What does this have to do with functions' "first-classness"? Python
> doesn't do nesting of lexical scopes -- which is a completely separate
> issue from that.
> restrictions apply to the ways you can handle them.
> ...
> You may dislike having to be explicit about the details
> of the new function object -- 'use the code of local
> function add, use the current variable look-up settings
> as the "global" namespace' -- and wish new.function
> defaulted them for you, but it doesn't. Big deal.

Actually it is a big deal. When you do

c = a + b

to construct the object c (say a and b are ints, although in this
case c isn't an object, but that doesn't change me point), you don't
have to say where you are getting a and b from (which environment or
namespace or whatever you want to call it). But if I want to
define a function I do have to be explicit about where I am
getting objects used in the function definition from. So functions
are not treated like other objects, and hence are not first class.

graham


Alex Martelli

unread,
Nov 18, 2000, 6:32:25 PM11/18/00
to
"graham" <grah...@telocity.com> wrote in message
news:B63C5C89.172D8%grah...@telocity.com...
[snip]

> But functions in Python aren't first class either. The most obvious
evidence
> of this is having to write manual closures.

What does this have to do with functions' "first-classness"? Python
doesn't do nesting of lexical scopes -- which is a completely separate

issue from that. A function-object in Python includes two references
to namespaces -- a 'local' one and a 'global' one -- and each such
namespace carries all the bindings it wants, without delegation
to other namespaces [well, the global namespace does such a
delegation, to the builtins' namespace; but the local one does
no delegation].

If anything, one might say that _namespaces_ aren't first-class
objects -- although that's not exactly the point: it's the _namespace
reference slots_ that aren't "first-class reference slots", in a way...
they're NOT able to hold references to just any object satisfying
a mapping's interface; rather, they can only refer to very specific
kinds of things. (Another peculiar kind of reference-slots are
those in class-objects: if set to refer to a function, they 'mutate'
that by wrapping it up as an unbound-method). There are many
other cases of reference-slots that are limited in some ways re
the kinds of things they can refer to; for example, the keys in a
dictionary must refer to immutable-objects; but these can most
often be framed in terms of 'satisfying a certain interface' -- e.g.,
in the case of dictionary-keys, "implementing __hash__" can
stand for "being immutable". This is not the case for namespaces.

But that is by the by. A function-object can be generated in
several ways, with different abilities and limitations (def, which
has the limitation of making you give it a name, and lambda,
which has the limitation of only allowing an expression as
the codeobject, 'automatically pick up' the current globals and
also build the codeobject that the function-object wraps;
new.function, instead, allows [and requires] you to specify
codeobject and globals explicitly).

(Similarly, for other objects, such as, say, strings; you can
generate them in several different ways -- as literals, or by
applying the builtin function str, or by calling the .join
method on another string object, etc).

Once you have generated (or otherwise obtained a reference to)
an object (be it a function, or a string) you can compare it
with other, store references to it in sundry places (including
passing it as an argument, binding to it a variable or an
object's attribute, etc), examine its attributes (have them
listed with dir, check for them with hasattr, fetch them with
getattr or with direct dot-syntax, etc), apply appropriate
operations (e.g., for a string, like some other objects but
not all, such operations include '+' but not 'calling'; for a
function, like some other objects but not all, they include
calling but not '+').

I.e., the objects are "first-class citizens": no special


restrictions apply to the ways you can handle them.

> How does this differ from
> wrapping a function in a callable object (which you can do in Python too).

A function *is* a callable object (which wraps, among other
things, a code-object, which is not callable). Of course, like
any other callable (or other object), it can be further 'wrapped'
(to any 'depth' you desire), but that does not in the least
affect its 'first-classness'.

The details of how you can (if you wish) 'prepare' various
sub-objects that the function-object wraps are a further,
and again completely different, issue. You may dislike the
lack of nested-lexical-scoping (which would allow one more
way to 'prime' the function's namespace), but in the end
it's not much more than an issue of syntax -- no wrapping
of function objects being involved.

E.g., consider a classical example:

>>> import new
>>> def adder(n):
def add(x):
return x+n
return new.function(add.func_code,vars())
>>> x=adder(5)
>>> x(20)
25
>>> y=adder(7)
>>> x(20)
25
>>> y(20)
27

You may dislike having to be explicit about the details
of the new function object -- 'use the code of local
function add, use the current variable look-up settings
as the "global" namespace' -- and wish new.function
defaulted them for you, but it doesn't. Big deal.


Alternatively (and as it happens more idiomatically),
the 'currying (from the right...)' idea...:

>>> def adder(n):
def add(x,n=n):
return x+n
return add

or equivalently

>>> def adder(n):
return lambda x,n=n: x+n

produce quite similar effects by other means (telling
the codeobject to look for n in the local dictionary,
and 'priming' that dictionary, rather than using the
new.function feature of specifying the _global_ one).

In none of these cases is the function object 'wrapped'
into anything (it _does_ 'wrap' references to a code
object and the two namespaces, as always), and no
matter which route you take to build/obtain it, you can
use it much like anything else. I.e., it's first-class...


Alex

Courageous

unread,
Nov 18, 2000, 7:35:30 PM11/18/00
to

>But functions in Python aren't first class either.

Well, nomenclature aside, I think what the poster meant was that in Python,
you can do this:

class Cool:
def f():
print "hello"

c = Cool()
f = c.f
f()

This is, behind the scenes, captured by Python as a true object, not just
a pointer. Once having gotten used to this and then gone back to using
other languages upon occasion, the lack of my ability to do this in these
other languages is a very big annoyance.

C//

Erno Kuusela

unread,
Nov 18, 2000, 9:47:48 PM11/18/00
to
>>>>> "graham" == graham <grah...@telocity.com> writes:

graham> Actually it is a big deal. When you do

graham> c = a + b

graham> to construct the object c (say a and b are ints, although
graham> in this case c isn't an object, but that doesn't change me

(why do you say c isn't an object?)

graham> point), you don't have to say where you are getting a and
graham> b from (which environment or namespace or whatever you
graham> want to call it). But if I want to define a function I do
graham> have to be explicit about where I am getting objects used
graham> in the function definition from. So functions are not
graham> treated like other objects, and hence are not first class.

it is exactly the same. in the "c = a + b" example, variables are only
looked up in the local and global scopes, same as when you are
defining a function. if a or b are in some lexically enclosing scope,
it won't work.

lexical scoping would be cool, otoh it could serve to obfuscate
code... (although not as much as list comprehensions)

-- erno

Alex Martelli

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
"graham" <grah...@telocity.com> wrote in message
news:B63CA023.172F7%grah...@telocity.com...
[snip]

> > You may dislike having to be explicit about the details
> > of the new function object -- 'use the code of local
> > function add, use the current variable look-up settings
> > as the "global" namespace' -- and wish new.function
> > defaulted them for you, but it doesn't. Big deal.
>
> Actually it is a big deal. When you do
>
> c = a + b
>
> to construct the object c (say a and b are ints, although in this
> case c isn't an object, but that doesn't change me point), you don't

But of course it IS an object, just like a function-object is one.
That is, by Python definition. If you're thinking 'class-instance'
when you say 'object', then neither ints not functions in Python
are 'objects' in THIS sense.

> have to say where you are getting a and b from (which environment or
> namespace or whatever you want to call it). But if I want to
> define a function I do have to be explicit about where I am
> getting objects used in the function definition from. So functions

No! Absolutely no difference.

c = lambda x, y=a, z=b: x + y + z

You don't have to be any more explicit about where a and b
are 'coming from' (which environment or namespace) in the
definition of this object (which you're binding to c) than you
do in the definition of the object that YOU were binding.

> are not treated like other objects, and hence are not first class.

They're treated exactly like every other object, and thus
are first-class.


Alex


graham

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Alex Martelli
> [on functions]

> They're treated exactly like every other object, and thus
> are first-class.

It's fine if you want to go on believing that Python has first class
functions, but the fact that you have to manually form closures for
functions means that they are not first class in the accepted (and
admittedly informal) definition of "first class". Ocaml, Haskell, etc
all have first class functions in the accepted meaning.

I am not criticising Python on this issue. All I am saying is that
to go around saying Python has first class functions is misleading,
particulary when comparing Python with other languagees, as the
original author did with Ruby. If you want to say that "Python has
first class functions, except that you have to manually form closures",
that's fine, but that's not the same as "having first class functions".

graham


Fredrik Lundh

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
"graham" wrote:
> It's fine if you want to go on believing that Python has first class
> functions, but the fact that you have to manually form closures for
> functions means that they are not first class in the accepted (and
> admittedly informal) definition of "first class".

do you have any references that support your definition
of "first class"?

(the references I've found all talk about how data values
are treated, not what syntax you have to use to create
those values...)

</F>

Erno Kuusela

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
>>>>> "graham" == graham <grah...@telocity.com> writes:

[snip argumentation for an unconventional definition of "first class"]

it would be beneficial for your argument if you could present
some evidence that your definition of "first class" is
shared by (preferably many) other people.

-- erno


Fredrik Lundh

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
"graham73" wrote:
> Actually it is a big deal. When you do
>
> c = a + b
>
> to construct the object c (say a and b are ints, although in this
> case c isn't an object, but that doesn't change me point), you don't
> have to say where you are getting a and b from (which environment or
> namespace or whatever you want to call it). But if I want to define a
> function I do have to be explicit about where I am getting objects used
> in the function definition from.

Really?

Python uses a two-scope model. For each name in a
function body, the compiler decides whether the name
is global or local at compile time. Names that are bound
inside the function (the argument to the function, names
that you assign to, names you import, etc) are considered
to be local, all other names are global.

Global names belong to the module in which the function
was defined, local names belong to the local namespace
(owned by the frame).

The resulting function object is a first-class object, and
can be treated like any other value in the system.

</F>

Jeremy Hylton

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
In article <kug0knh...@lasipalatsi.fi>,

(Any?)

The normal definition of "first class" is an object that can be named
and treated as data at runtime. A first class object can be bound to a
variable name, passed as an argument to a function, or returned from a
function. The term has nothing to do with scoping rules.

I also wanted to mention that I am working on a PEP to add nested
lexical scoping to Python. I hope to finish it before the PEP deadline.
It's PEP 227 at http://python.sourceforge.net/peps/

--
-- Jeremy Hylton, <http://www.python.org/~jeremy/>


Sent via Deja.com http://www.deja.com/
Before you buy.

Gareth McCaughan

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
graham wrote:

> It's fine if you want to go on believing that Python has first class
> functions, but the fact that you have to manually form closures for
> functions means that they are not first class in the accepted (and

> admittedly informal) definition of "first class". Ocaml, Haskell, etc
> all have first class functions in the accepted meaning.

Python's functions are first class. They are not lexical closures.
That's all.

graham

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Fredrik Lundh:

> "graham" wrote:
>> It's fine if you want to go on believing that Python has first class
>> functions, but the fact that you have to manually form closures for
>> functions means that they are not first class in the accepted (and
>> admittedly informal) definition of "first class".
>

> do you have any references that support your definition
> of "first class"?
>
> (the references I've found all talk about how data values
> are treated, not what syntax you have to use to create
> those values...)

You should ask this question in comp.lang.functional.

graham


graham

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Erno Kuusela:

>>>>>> "graham" == graham <grah...@telocity.com> writes:
>
> [snip argumentation for an unconventional definition of "first class"]
>
> it would be beneficial for your argument if you could present
> some evidence that your definition of "first class" is
> shared by (preferably many) other people.

My definition is not unconventional. Go talk to the knowledgable
crowd in comp.lang.functional.

graham


graham

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Fredrik Lundh:

> Python uses a two-scope model. For each name in a
> function body, the compiler decides whether the name
> is global or local at compile time. Names that are bound
> inside the function (the argument to the function, names
> that you assign to, names you import, etc) are considered
> to be local, all other names are global.
>
> Global names belong to the module in which the function
> was defined, local names belong to the local namespace
> (owned by the frame).
>
> The resulting function object is a first-class object, and
> can be treated like any other value in the system.

By this definition C has first class functions. Sure you have
the minor inconvenience of having to take pointers to functions,
and using dereferencing to call them. But that's a minor point.
So does C have first class functions?

graham


graham

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Jeremy Hylton

> The normal definition of "first class" is an object that can be named
> and treated as data at runtime. A first class object can be bound to a
> variable name, passed as an argument to a function, or returned from a
> function. The term has nothing to do with scoping rules.

So by this definition C has first class functions. Does it?

graham

graham

unread,
Nov 19, 2000, 3:00:00 AM11/19/00
to
Gareth McCaughan

> graham wrote:
>
>> It's fine if you want to go on believing that Python has first class
>> functions, but the fact that you have to manually form closures for
>> functions means that they are not first class in the accepted (and
>> admittedly informal) definition of "first class". Ocaml, Haskell, etc
>> all have first class functions in the accepted meaning.
>
> Python's functions are first class. They are not lexical closures.
> That's all.

As I posted to others your definition then says that C has first class
functions. Does it?

graham


Fredrik Lundh

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
"graham73" wrote:
> By this definition C has first class functions. Sure you have
> the minor inconvenience of having to take pointers to functions,
> and using dereferencing to call them. But that's a minor point.
> So does C have first class functions?

According to the usual definition, C has first-class function pointers,
not first-class functions -- you cannot rename functions, you cannot
have anonymous functions, you cannot return code from a function,
etc.

(See the comp.compilers archives for long discussions on this topic)

If you prefer you're own definition, that's fine, but I'm afraid "graham73
told me he'd seen it on usenet" isn't really that convincing...

</F>

Alex Martelli

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
"graham" <grah...@telocity.com> wrote in message
news:B63D9C65.17342%grah...@telocity.com...

> Alex Martelli
> > [on functions]
> > They're treated exactly like every other object, and thus
> > are first-class.
>
> It's fine if you want to go on believing that Python has first class
> functions, but the fact that you have to manually form closures for
> functions means that they are not first class in the accepted (and
> admittedly informal) definition of "first class". Ocaml, Haskell, etc

Here's an "accepted definition of first-class", from a typical
(and, incidentally, quite usable) Scheme course:
http://www.cs.odu.edu/~zeil/cs355/Handouts/schemedoc/schemedoc/node13.html

"""
In Scheme, as in most dialects of Lisp, functions are first-class. This
means that they are values, just like any other data type--they may be
passed as arguments to functions and returned as values of functions.
"""

*Are values like any other data type -- may be passed as arguments and
returned as values*. THIS is the typical "accepted, admittedly informal"
definition.


Similarly, take a typical introduction to functional programming, at
http://cs.wwc.edu/~aabyan/221_2/PLBOOK/Functions.html:

"LISP ... in 1958 ... provided for recursion, first-class functions ...
dynamic rather than static scope rules". Gist of the quote: LISP in
the 1958 version is said to provide first-class functions, although
it lacks any static scoping but provides dynamic scoping instead.


Not all authors agree on this (that early LISP provided first-class
functions), but it does appear to be the most-widespread opinion
about this issue.


Taking Charles Elkan's lectures at
http://www-cse.ucsd.edu/graduate/Comps/vogt/proglang/elkan.lectures:

"""
In a nutshell, at "definition time", when an abstraction is evaluated
to give a "function value":
- under static scoping the function value is a closure
which saves the current environment
- under dynamic scoping, only the abstraction expression is saved.
"""

we see that Python is far closer to what Elkan defines as 'static
scoping' -- it just doesn't (currently) define "the current
environment" to include any NESTING (lexical or otherwise).

Of course, Elkan's explicit definition of "first-class" is:
"""
FIRST-CLASS VALUES

Defn: A value is first-class if it can be used in all contexts
where other values can be used, in particular:
- as a literal value
- as part of a larger value
- as a function argument
- as a function result
"""


Are you disputing that THIS is what a value "being first-class"
means? And/or are you disputing that function-objects in Python
meet this definition? Besides the arguments/results parts, they
can surely be used 'as part of a larger value' (a tuple, or list,
or dictionary, ...), and as literals too, e.g.:

atuple = (1, "2", 3.0, lambda x: 4+x, 5+0j, 6L, [7], (8,), {9:10})

This 'larger value' (a 9-elements tuple) uses as its "parts"
various literals of different 'first-class' Python types --
each with its own, different syntax -- the fourth one being
a function.

"All contexts" in Elkan's definition needs to be taken _in
context_, of course, -- e.g.,
atuple[i] + 7
is OK for i in (0,2,4,5), but not otherwise -- that doesn't
mean strings, functions, lists, tuples, and dictionaries
aren't first-class, just that "addition of 7" is not defined
for these particular types, while it is for integers, floats,
complex and longs. Just trying to forestall some cavils...:-).


> all have first class functions in the accepted meaning.
>

> I am not criticising Python on this issue. All I am saying is that
> to go around saying Python has first class functions is misleading,

No, it's just applying the common-or-garden definition. A function
is first-class, but it's (currently) not a (nested) lexical closure.
It's not in issue of criticism of praise, but one of precision in
the use of words.

Is the following idiom familiar at all...?

(defun make-adder (n)
(lexical-let ((n n))
(function (lambda (m) (+ n m)))))

The result of make-adder isn't any less 'first-class' because an
explicit lexical-let was needed to make it into a lexical-closure,
in a Lisp dialect that otherwise binds dynamically. This is not
a _defense_ of dynamical binding (nor of Python's current, limited
form of statical binding) -- just a *terminological clarification*.

Humpty-Dumpty-ish use of words is not correct or acceptable on
a public technical forum, in my opinion.


> particulary when comparing Python with other languagees, as the
> original author did with Ruby. If you want to say that "Python has
> first class functions, except that you have to manually form closures",
> that's fine, but that's not the same as "having first class functions".

You don't *have* to 'form closures' at all -- you form them if
and when you feel a need for them. This issue has no bearing
on 'first-classness' of functions, and it would therefore be
totally inappropriate to tag it in an "exception clause" to
an assertion about said first-classness -- as if it was somehow
a LIMITATION of the first-classness aspect, when it just isn't.

It would be like saying something like, e.g., 'Python has first
class unlimited-precision integers (bignums), except that you
have to syntactically denote them with a trailing L'. The lack
of, e.g., Smalltalk-ish implicit conversion between fixnums and
bignums may be a plus or a minus, but it has nothing to do with
the *first-classness* of such numbers, and it wold be misleading
to imply or assert it does.


Alex


Hrvoje Niksic

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
"Alex Martelli" <ale...@yahoo.com> writes:

> """
> In Scheme, as in most dialects of Lisp, functions are first-class. This
> means that they are values, just like any other data type--they may be
> passed as arguments to functions and returned as values of functions.
> """

The last part is what distinsguishes "first-class" from
"second-class". In C, for instance, functions might be called
second-class objects because you can pass them to functions, but you
cannot meaningfully return new ones from functions.

The whole story about the enclosing environment is a red herring
anyway, because it relies on side-effects. When using proper
*functions* in Python, they are always first-class objects, *and* you
need no namespace games for them to work.

If you're using side-effects, then it's up to the language whether
they will be implicit (inferred from the enclosing lexical
environment) or explicit (the "self" parameter of a bound method or
optional parameters in function definition).

Jeremy Hylton

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
In article <B63DFA7F.1738B%grah...@telocity.com>,

graham <grah...@telocity.com> wrote:
> Jeremy Hylton
> > The normal definition of "first class" is an object that can be
named
> > and treated as data at runtime. A first class object can be bound
to a
> > variable name, passed as an argument to a function, or returned
from a
> > function. The term has nothing to do with scoping rules.
>
> So by this definition C has first class functions. Does it?
>
> graham

As /F has already pointed out, C's function pointers are a lot like
first-class functions, but they are somewhat limited. You can't create
a function object inside another function and then return a pointer to
it.

Is there a reason you continue to disagree with all of us without
offering in response a definition of your own or some evidence that
anyone else uses it?

Darren New

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
graham wrote:
>
> Jeremy Hylton
> > The normal definition of "first class" is an object that can be named
> > and treated as data at runtime. A first class object can be bound to a
> > variable name, passed as an argument to a function, or returned from a
> > function. The term has nothing to do with scoping rules.
>
> So by this definition C has first class functions. Does it?

No. C has first-class pointers to functions.

You can't treat a function as data at runtime in C. You can't inspect it,
copy it, assign it to a variable, or pass it or return it as an argument to
a function.

Function pointers are not the same as functions.

--
Darren New / Senior MTS & Free Radical / Invisible Worlds Inc.
San Diego, CA, USA (PST). Cryptokeys on demand.

Alex Martelli

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
"Hrvoje Niksic" <hni...@arsdigita.com> wrote in message
news:sxsvgti...@florida.arsdigita.de...

> "Alex Martelli" <ale...@yahoo.com> writes:
>
> > """
> > In Scheme, as in most dialects of Lisp, functions are first-class. This
> > means that they are values, just like any other data type--they may be
> > passed as arguments to functions and returned as values of functions.
> > """
>
> The last part is what distinsguishes "first-class" from
> "second-class". In C, for instance, functions might be called

This is exactly my point (although I also quoted more detailed
definitions).

> The whole story about the enclosing environment is a red herring
> anyway, because it relies on side-effects. When using proper
> *functions* in Python, they are always first-class objects, *and* you
> need no namespace games for them to work.

Not exactly. A side-effect is something that _modifies_ the
environment; a perfectly proper Python function without side
effects can perfectly well _use_ existing bindings (without
modifying them).

In other words, I don't agree with your definition of "side
effect", as I don't think it reflects common usage, just as
I don't agree with graham's definition of "first class", ditto.

The environment issue is not a 'red herring' per se, and does
not hinge on side effects. It _is_, however, an orthogonal
issue to that of function's first-classness.


Alex


Quinn Dunkan

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
On 20 Nov 2000 14:52:19 +0100, Hrvoje Niksic <hni...@arsdigita.com> wrote:

>"Alex Martelli" <ale...@yahoo.com> writes:
>
>> """
>> In Scheme, as in most dialects of Lisp, functions are first-class. This
>> means that they are values, just like any other data type--they may be
>> passed as arguments to functions and returned as values of functions.
>> """
>
>The last part is what distinsguishes "first-class" from
>"second-class". In C, for instance, functions might be called
>second-class objects because you can pass them to functions, but you
>cannot meaningfully return new ones from functions.
>
>The whole story about the enclosing environment is a red herring
>anyway, because it relies on side-effects. When using proper
>*functions* in Python, they are always first-class objects, *and* you
>need no namespace games for them to work.

I'm not quite sure I understand:

def curried_add(x):
def f(y, x=x): # <- namespace game here
return x+y
return f

Surely you'll agree that's a "real" function :)

My own personal definition of 'first class functions' wants functions to live
in the same namespace as other values, but that would probably disqualify
lisp, so obviously my defn is out of sync with the rest of the world's :)
I'd rather write in scheme anyway :)

I think python's scoping is not a bug or a feature, it's a design tradeoff.
Whether it's a worthwhile tradeoff is a matter of debate, but it is consistent
with the rest of the language, which tends to trade the ease of certain idioms
for explicit behaviour. Indentation sacrifices the 'everything on one line'
and 'invent your own indentation style' idioms for explicit and consistent
block notation. Putting most functionality in modules and encouraging
qualified imports sacrifices concise typing for explicit naming. I think most
people would agree that the first two sacrifices are worth their tradeoffs.
When we get to sacrificing a number of functional idioms for explicit
namespaces, people start to disagree because functional idioms are useful.

Not that that little bit of content-less summary had anything to do with the
point, but hey, it's usenet. And now the people from the grammar thread,
attracted by my use of 'that that' will probably come over and prolong this
thread further (farther?) :)

Philip 'Yes, that's my address' Newton

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
On Sun, 19 Nov 2000 21:45:36 -0500, graham <grah...@telocity.com> wrote:

> Jeremy Hylton
> > The normal definition of "first class" is an object that can be named
> > and treated as data at runtime. A first class object can be bound to a
> > variable name, passed as an argument to a function, or returned from a
> > function. The term has nothing to do with scoping rules.
>
> So by this definition C has first class functions. Does it?

No. You can only do all the above with pointers to functions, not with functions
themselves.

Cheers,
Philip
--
Philip Newton <nospam...@gmx.li>
If you're not part of the solution, you're part of the precipitate.

Philip 'Yes, that's my address' Newton

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
On Sun, 19 Nov 2000 21:37:24 -0500, graham <grah...@telocity.com> wrote:

> By this definition C has first class functions. Sure you have
> the minor inconvenience of having to take pointers to functions,
> and using dereferencing to call them. But that's a minor point.
> So does C have first class functions?

Minor inconvenience? IMO this shows that functions are not first class objects
in C. They can't be manipulated in the same way that, for example, integers can.
You don't need to fiddle around with pointers and dereferencing to pass a number
around.

Gareth McCaughan

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
"graham" wrote:

> >> It's fine if you want to go on believing that Python has first class
> >> functions, but the fact that you have to manually form closures for
> >> functions means that they are not first class in the accepted (and
> >> admittedly informal) definition of "first class". Ocaml, Haskell, etc

> >> all have first class functions in the accepted meaning.
> >

> > Python's functions are first class. They are not lexical closures.
> > That's all.
>

> As I posted to others your definition then says that C has first class
> functions. Does it?

Did I say what my definition is?

I wouldn't say that C has first-class functions. You can't
in any sense make them at runtime, most notably. However,
it *is* possible to do a lot with C's function pointers;
they're certainly *much* nearer to being "first-class" than
functions in Pascal or FORTRAN, for instance.

Ultimately, the term "first class" is pretty badly
ill-defined, whether you're talking about functions
or classes or types or whatever. The meaning of the
term is a matter of consensus. I think the consensus
is that having lexical closures is (1) a very good
thing, but (2) not necessary for functions to be
first class. (If #2 is wrong, then LISP 1.5 did not
have first class functions. I find that a very odd
position.)

Here's one criterion. It's not a serious attempt at a
rigorous definition; just a handy indicator. "Is it
possible to write a function that takes two functions
of one argument each and returns the composition of
those functions?".

In Python, you can do this.

def compose(f,g):
def _(x,g=g): return f(g(x))
return _

In modern Lisps, you can do it.

(defun compose (f g)
(lambda (x) (f (g x))))

In C, you can't quite do it. The first issue is that
you have to choose your types, but it's not fair to
regard that as conclusive because otherwise only
dynamically typed languages can have "first class
functions" -- hopeless. The other problem is that
you have no good way of doing the environment thing.
The best I can come up with is:

typedef int Func(int);

static Func_ *f_, *g_;

int c_(int x) {
return f_(g_(x));
}

Func * compose(Func * f, Func * g) {
f_=f; g_=g;
return c_;
}

IF we're allowed to apply some syntactic sugar, then
of course we can do it by emulating closures. USe the
preprocessor to provide some syntax like CALL1(f,x),
and so on. But then your closure calls don't look like
ordinary function calls.

In LISP 1.5, you can do it, but it's painful. The first
attempt is this:

(DEFUN COMPOSE (F G)
(LAMBDA (X) (F (G X))))

Same program as for Common Lisp above (except that they
didn't do lowercase back then). The only problem is that
it doesn't work, because LISP 1.5 was dynamically scoped,
and you end up with a problem a bit like the one with the
C code. Having a real memory management system and a bunch
of other interesting things helps, though, so you could
try something like

(DEFUN COMPOSE (F G)
(LET ((FS (GENSYM))
(GS (GENSYM)))
(SET FS F)
(SET GS G)
(EVAL (LIST 'LAMBDA
(LIST 'X)
(LIST FS (LIST GS X))))))

WHICH IS ... excuse me ... which is so full of pain it's
hard to believe, but will do just about the right thing.
It may also leak memory like there's no tomorrow, if the
system can't GC symbols. (I don't know whether it could.)
Note that (SET X Y) doesn't mean what you might think.
There may well be a better LISP 1.5 solution. Would
anyone who actually used it for real, way back when,
like to comment?

Conclusion so far: Common Lisp and Python certainly have
first class functions; LISP 1.5 just barely has them; C
doesn't. Lexical closures help, but they aren't necessary
if the language has other features that compensate.

Marcin 'Qrczak' Kowalczyk

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
Mon, 20 Nov 2000 21:31:46 +0100, Philip 'Yes, that's my address' Newton <nospam...@gmx.li> pisze:

> > So by this definition C has first class functions. Does it?
>
> No. You can only do all the above with pointers to functions,
> not with functions themselves.

It is irrelevant whether you call them functions or function pointers.
Terminology and minor syntactic nuances don't matter.

What matters is that in C you cannot define a function inside a local
environment. Thus a function is only a piece of code, without any data
attached, because anything it can refer to must be global.

Python is a lot better in this respect. But it's not as good as many
other languages where you don't need to enumerate pieces of the local
environment mentioned in the inner function.

C cannot be really fixed. If C allowed local functions (as gcc does),
the major problem is still the lifetime of local objects of the
outer function mentioned in the inner one. If they must disappear
where the outer function terminates, the solution is half-baked:
you can use such function as long as the outer function is running,
but it cannot exist on its own after its birth place is over. If
these objects don't disappear, then how long do they live? C lacks
garbage collection and this is the problem. These objects should be
attached to the function object, but various function objects of the
same type can have different patterns of objects attached, so they
cannot be freed explicitly from outside.

I believe that Python can be fixed. It's not obvious how to define it
however, because variable declarations are implicit. Variables begin
their lives with the first assignment, which is a dynamic concept
and does not define a scope.

Ruby solves it by letting the syntactic assignment define a scope.
Smalltalk has explicit variable declarations, as languages with static
type systems do. Perl has explicit variable declarations using the
"my" keyword, with other variables being global by default. Lisp does
it like Perl.

No solution is perfect if there are no explicit variable declarations:
there are perverse programs when the variable in question may belong
to inner or outer scope, it does influence the result, and it is
not deducible by the compiler. But in reality variables are used at
least once in the outermost scope they belong to, and if they don't,
it's easy to add an artificial usage. So I propose a variant of the
Ruby solution. E.g. that any use of a local variable defines a scope
(and of course formal parameters and function definitions too). All
uses of the name as a local variable in inner scopes refer to the
same variable. I see no reason to disallow assignments in inner scopes.

Deeply nested functions won't be used much in practice, but at least
there would be no need of this annoying passing by default arguments
and local recursive functions will work normally.

--
__("< Marcin Kowalczyk * qrc...@knm.org.pl http://qrczak.ids.net.pl/
\__/
^^ SYGNATURA ZASTĘPCZA
QRCZAK

James Logajan

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
Gareth McCaughan wrote:
> I wouldn't say that C has first-class functions. You can't
> in any sense make them at runtime, most notably.

Sure you can. I thought everyone knew how to do that. Just because people
don't do it much these days doesn't mean its not possible.

Never could figure out why it was okay in Lisp and other fancy-pants
languages to do self-modifying code but not in C or assembler....

Erik Max Francis

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
James Logajan wrote:

> Sure you can. I thought everyone knew how to do that. Just because
> people
> don't do it much these days doesn't mean its not possible.

It's not possible in Standard C.

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE
/ \ Gods are born and die, but the atom endures.
\__/ Alexander Chase
Official Buh rules / http://www.alcyone.com/max/projects/cards/buh/
The official rules to the betting card game, Buh.

Erik Max Francis

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
Marcin 'Qrczak' Kowalczyk wrote:

> It is irrelevant whether you call them functions or function pointers.
> Terminology and minor syntactic nuances don't matter.

You can say that if you like, but the C Standard makes a very clear
distinction between a function and a function pointer.

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE

/ \ All bad poetry springs from genuine feeling.
\__/ Oscar Wilde
Interstelen / http://www.interstelen.com/
A multiplayer, strategic, turn-based Web game on an interstellar scale.

Andrew Dalke

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
James Logajan wrote:
>Gareth McCaughan wrote:
>> I wouldn't say that C has first-class functions. You can't
>> in any sense make them at runtime, most notably.
>
>Sure you can. I thought everyone knew how to do that. Just because people
>don't do it much these days doesn't mean its not possible.

One of my favorite tricks is to write the C code to a file then
compile it to a shared library and dlopen it :)

Andrew
da...@acm.org


Conrad Schneiker

unread,
Nov 20, 2000, 3:00:00 AM11/20/00
to
Hi,

Just van Rossum wrote:

> Lyle Johnson wrote:
> ...
> One odd thing I came across: while in Ruby apparently everything is an
> instance (no difference between types and classes) I read somewhere that
> functions and methods are _not_ first class citizens.

I think this notion originally spread from an on-line Ruby article last
spring. Since the above comment seemed somewhat contrary to what I had
subsequently read elsewhere (IIRC), I asked Ruby's creator (aka Matz) about
this. His reply (in
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/6475 and on
comp.lang.ruby earlier today) was:

# |Is this (literally) correct, or is this correct subject to some important
# |but unstated qualifications? And if so, was there a good (for some
# |purposes) trade-off involved?
#
# It used to be correct.
# Methods became first class citizens on Mar. 3 1998.
#
# In Ruby, unlike Python, method invocation does not generate method
# object internally.
#
# matz.

Conrad

Rainer Deyke

unread,
Nov 20, 2000, 9:20:38 PM11/20/00
to
"James Logajan" <Jam...@Lugoj.Com> wrote in message
news:3A19BFCC...@Lugoj.Com...

> Gareth McCaughan wrote:
> > I wouldn't say that C has first-class functions. You can't
> > in any sense make them at runtime, most notably.
>
> Sure you can. I thought everyone knew how to do that. Just because people
> don't do it much these days doesn't mean its not possible.
>
> Never could figure out why it was okay in Lisp and other fancy-pants
> languages to do self-modifying code but not in C or assembler....

It is possible to write self-modifying code in assembler. It is *not*
possible to write self-modifying code in C without relying on undefined
behavior. There is no guarantee that pointers to functions can be converted
to or from pointers to data (including pointers to void).


--
Rainer Deyke (ro...@rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor


Hrvoje Niksic

unread,
Nov 20, 2000, 9:25:51 PM11/20/00
to
"Rainer Deyke" <ro...@rainerdeyke.com> writes:

> It is possible to write self-modifying code in assembler.

You might have a hard time doing that on today's Unix systems. By
default, your code will be placed to the text segment, and attempts to
modify it will fail with a SIGSEGV.

Erno Kuusela

unread,
Nov 21, 2000, 1:03:51 AM11/21/00
to
>>>>> "Hrvoje" == Hrvoje Niksic <hni...@arsdigita.com> writes:

Hrvoje> You might have a hard time doing that on today's Unix
Hrvoje> systems. By default, your code will be placed to the text
Hrvoje> segment, and attempts to modify it will fail with a
Hrvoje> SIGSEGV.

you can always copy the code you want to modify to the heap or
the stack.

read bugtraq lately?-)

-- erno

Suchandra Thapa

unread,
Nov 21, 2000, 3:00:00 AM11/21/00
to
graham <grah...@telocity.com> wrote:
>Jeremy Hylton
>> The normal definition of "first class" is an object that can be named
>> and treated as data at runtime. A first class object can be bound to a
>> variable name, passed as an argument to a function, or returned from a
>> function. The term has nothing to do with scoping rules.
>
>So by this definition C has first class functions. Does it?
>

C doesn't let you create functions at run time and functions aren't
equivalent to data in C. I agree with Jeremy on his definition of a
first class object. Basically a first class object can be handled the
same way data is.
I believe lisp has had first class functions since fairly early in
its inception however it did not have lexical scoping and lexical closures
until recently. In fact, I think emacs lisp is still dynamically scoped.
I don't think anyone really thinks that lisp doesn't have first class
function however.


--
------------------------------------------------------------------
|
Suchandra Thapa | "There are only two kinds of math books.
s-th...@SPAMuchicago.edu | Those you cannot read beyond the first
| sentence, and those you cannot read
| beyond the first page."
| -C.N. Yang
------------------------------------------------------------------

Suchandra Thapa

unread,
Nov 21, 2000, 3:00:00 AM11/21/00
to
graham <grah...@telocity.com> wrote:
>
>By this definition C has first class functions. Sure you have
>the minor inconvenience of having to take pointers to functions,
>and using dereferencing to call them. But that's a minor point.
>So does C have first class functions?

You are missing the point that C does not allow you to
dynamically create new functions at runtime. You can create
new data types using a malloc but you can only use function pointers
to manipulate functions that exist at compile time. This creates
a clear distinction between say an integer that which you create new
instances of at runtime and functions which can only be created at
compile time. Thus, functions don't have the same rights assigned to
them as data types and are second class in comparision. If there
is no distinction between data and functions, functions are first
class.
The only major quibble you can really have about python's handling
of functions is that runtime creation of objects are limited by
the restrictions on the lambda function. However, you can get
around this by chaining a bunch of lambdas together.

Alex Martelli

unread,
Nov 21, 2000, 3:00:00 AM11/21/00
to
"Suchandra Thapa" <sst...@harper.uchicago.edu> wrote in message
news:slrn91htg2....@localhost.localdomain...
[snip]

> The only major quibble you can really have about python's handling
> of functions is that runtime creation of objects are limited by
> the restrictions on the lambda function. However, you can get
> around this by chaining a bunch of lambdas together.

The "new.function" function (in standard module 'new') lets you
"runtime-create" function objects in Python (you supply to it a
code-object, which you can get/create in various ways, as well
as a global-namespace dict, and, optionally, a name-string and
a tuple of default values for arguments). Also, 'def' is an
executable statement: each time it's executed, it returns a NEW
function-object, too (much like a new.function, but with the
code-object being the body of the 'def', the name being the
identifier right after the 'def' keyword, and the global namespace
being the one currently in use). lambda, in other words, is just
one of several ways that Python offers to create function objects
at runtime; its limitations (that the code-object be just an
expression, not a statement-suite) only affect that specific
syntax, not other ones.

For example, say we want to build, at runtime, a list of
functions, such that the i-th function in the list will
take one argument x (a string) and return a list composed
of '' (0 repetitions of x), x, x+x, ..., up to x*(i-1).

We can do it with lambda and list comprehensions, of
course:

>>> repeater = []
>>> for i in range(6):
... repeater.append(lambda x,i=i: [x*j for j in range(i)])
...
>>> for x in repeater: x('bo')
...
[]
['']
['', 'bo']
['', 'bo', 'bobo']
['', 'bo', 'bobo', 'bobobo']
['', 'bo', 'bobo', 'bobobo', 'bobobobo']
>>>

But suppose we didn't have list comprehensions, so that
the bodies of the functions we want to generate and put
in the list would really need to be statement suites
(e.g., to have loops in them). Because def is an
executable statement and returns a new function object
each time it's executed, it's just as easy, if more
verbose:

>>> rop=[]
>>> for i in range(6):
... def f(x,i=i):
... result = []
... for j in range(i):
... result.append(x*j)
... return result
... rop.append(f)
...
>>> for x in rop: x('bo')
...
[]
['']
['', 'bo']
['', 'bo', 'bobo']
['', 'bo', 'bobo', 'bobobo']
['', 'bo', 'bobo', 'bobobo', 'bobobobo']
>>>

"See, ma, no lambda!":-). def works just as well as
lambda and without its limitation -- it does have its
own, namely that you have to associate a *name* to
the function you're defining, but that's no biggie.

Just for fun, here's a mixed-approach based on using
new.function (I've kept the functionbody concise by
using a list comprehension again, but it makes no
difference):

>>> def repeater(n):
... def f(x):
... return [x*j for j in range(i)]
... rep=[]
... for i in range(n):
... glo={'range':range, 'i':i}
... rep.append(new.function(f.func_code,glo))
... return rep
...
>>> rap=repeater(6)
>>> for x in rap: x('bo')
...
[]
['']
['', 'bo']
['', 'bo', 'bobo']
['', 'bo', 'bobo', 'bobobo']
['', 'bo', 'bobo', 'bobobo', 'bobobobo']
>>>

This has one big difference -- here, we pass an explicitly
built *global* namespace, rather than 'priming' the *local*
namespace with the argument-with-default idiom. Which is
why we need to bind 'range' in that namespace -- to avoid
a NameError on it!

But, isn't this *terrible*, to have to manually build a
namespace this way...?

Pah! Who ever said we have to do it manually? *Explicitly*,
yes, but if we like this idiom so much that we want to
automate the process, hey, Python *is* a pretty powerful
language, you know, and it *does* have first-class functions
and code-objects and decent reflection abilities, so,
for example, we can code:

def func_env(func, vars):
code = func.func_code
glo = {}
for name in code.co_names:
if not name in code.co_varnames:
try: glo[name] = eval(name, vars)
except NameError: pass
return new.function(code, glo)

This extracts the code-object wrapped in a function-object;
loops over all the names used in this code-object, but
skips those that have been identified as local variable
names, only treating the 'global' names; tries to prime
the 'glo' dictionary with the current binding of each such
name in a supplied 'vars' namespace (dictionary), ignoring
errors from unbound names; finally, wraps up the codeobject
and the new dictionary (namespace) into a new function
object, which it returns as its results.

In other words, it roughly emulates, explicitly, the implicit
binding-process (environment-construction) that appears to be
the idiom so keenly desired here -- as long as 'vars' is
passed in as the desired 'enclosing namespace', of course.

That is easy to arrange, e.g. by recoding 'repeater' as:

def repeater(n):
def f(x):
return [x*j for j in range(i)]
rep=[]
for i in range(n):
rep.append(func_env(f,vars()))
return rep

since 'vars()' returns exactly the 'current composite
namespace' (at least as far as _reading_ from it is
concerned...).


There are still several open issues with this approach --
what happens if the codeobject being wrapped plays highly
dynamic tricks, or just tries to _re-bind_ globals. But,
for "well-behaved" codeobjects, wrapping them like this
is quite OK -- if you're really keen about such idioms.
(For much-wider applicability, you might have to get in
at a lower-level, tweaking/hacking the bytecode).

"Explicit is better than implicit" is a Python mantra --
here, you get to code the wrapping-function func_env, which
takes a function object and an environment as its args,
and returns a new function object using that environment,
so you can tweak its semantics to taste...:-).


Alex


Alex Martelli

unread,
Nov 21, 2000, 3:00:00 AM11/21/00
to
"Suchandra Thapa" <sst...@harper.uchicago.edu> wrote in message
news:slrn91ht1l....@localhost.localdomain...
[snip]

> until recently. In fact, I think emacs lisp is still dynamically scoped.

It is, and you can import and use a CL-emulation package (and
explicitly bind some variables _lexically_, with such typical
idioms as...:
(lexical-let ((n n)) ...
if and when you need them).


Alex

gbr...@cix.compulink.co.uk

unread,
Nov 21, 2000, 3:00:00 AM11/21/00
to
Gareth McCaughan wrote:

> Here's one criterion. It's not a serious attempt at a
> rigorous definition; just a handy indicator. "Is it
> possible to write a function that takes two functions
> of one argument each and returns the composition of
> those functions?".
>
> In Python, you can do this.
>
> def compose(f,g):
> def _(x,g=g): return f(g(x))
> return _

Almost. You can do this:

>>> def compose(f,g):
... def temp(x, f=f, g=g):
... return f(g(x))
... return temp
...
>>> compose(len, str)(300)
3


or even this:

>>> def compose(f,g):
... return lambda x, f=f, g=g: f(g(x))
...
>>> compose(len, str)(20)
2


Graham B

James Logajan

unread,
Nov 21, 2000, 3:00:00 AM11/21/00
to
Andrew Dalke wrote:

>
> James Logajan wrote:
> >Gareth McCaughan wrote:
> >> I wouldn't say that C has first-class functions. You can't
> >> in any sense make them at runtime, most notably.
> >
> >Sure you can. I thought everyone knew how to do that. Just because people
> >don't do it much these days doesn't mean its not possible.
>
> One of my favorite tricks is to write the C code to a file then
> compile it to a shared library and dlopen it :)

Very good. But that is no trick; that is one proper way to accomplish the
task.

Philip 'Yes, that's my address' Newton

unread,
Nov 21, 2000, 3:00:00 AM11/21/00
to

Those segments are often (sometimes?) marked "read/write, no execute", so you
may not be able to branch to the code and have it executed.

Greg Ewing

unread,
Nov 21, 2000, 7:57:55 PM11/21/00
to
Suchandra Thapa wrote:
>
> You are missing the point that C does not allow you to
> dynamically create new functions at runtime.

If that's a requirement, then Haskell doesn't have
first-class functions either. I think the functional
programming people might disagree about that.

--
Greg Ewing, Computer Science Dept, University of Canterbury,
Christchurch, New Zealand
To get my email address, please visit my web page:
http://www.cosc.canterbury.ac.nz/~greg

Greg Ewing

unread,
Nov 21, 2000, 8:08:57 PM11/21/00
to
Conrad Schneiker wrote:
>
> I asked Ruby's creator (aka Matz) about this. His reply was:

>
> # In Ruby, unlike Python, method invocation does not generate method
> # object internally.

Could Python be optimised to skip the creation of a
bound-method object when it's not needed?

Seems to me the compiler could recognise the
pattern

expr.attribute(params,...)

and generate a single call-method operation instead
of a get-attribute followed by a call-object.

That would eliminate the creation and destruction
of untold billions of bound-method objects worldwide
every day!

Gareth McCaughan

unread,
Nov 21, 2000, 9:14:59 PM11/21/00
to
Graham Breed wrote:

[I said:]


> > In Python, you can do this.
> >
> > def compose(f,g):
> > def _(x,g=g): return f(g(x))
> > return _
>
> Almost. You can do this:
>
> >>> def compose(f,g):
> ... def temp(x, f=f, g=g):
> ... return f(g(x))
> ... return temp

Oops! I wonder why I forgot to deal with f when I remembered
the corresponding thing in the C version. Ah well, such is
human fallibility.

Michael Hudson

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
Greg Ewing <gr...@cosc.canterbury.ac.nz> writes:

> Conrad Schneiker wrote:
> >
> > I asked Ruby's creator (aka Matz) about this. His reply was:
> >
> > # In Ruby, unlike Python, method invocation does not generate method
> > # object internally.
>
> Could Python be optimised to skip the creation of a
> bound-method object when it's not needed?

Well, they're cached (in the same style as frames), so at least
there's not one being allocated for every method call.

> Seems to me the compiler could recognise the
> pattern
>
> expr.attribute(params,...)
>
> and generate a single call-method operation instead
> of a get-attribute followed by a call-object.

Would be awkward, becase the I think compiler gets things in the order

com_name "expr"
com_attr "attribute"
... params
com_call

(or whatever the node names are). Besides, don't you think the coded
for CALL__FUNCTION is hairy enough already?

Don't let me stop you trying though...

> That would eliminate the creation and destruction
> of untold billions of bound-method objects worldwide
> every day!

Well, maybe a few dozen per Python process... I don't think that's
billions is it ... yet?

Cheers,
M.

--
GET *BONK*
BACK *BONK*
IN *BONK*
THERE *BONK* -- Naich using the troll hammer in cam.misc

Alex Martelli

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
"Greg Ewing" <gr...@cosc.canterbury.ac.nz> wrote in message
news:3A1B1A13...@cosc.canterbury.ac.nz...

> Suchandra Thapa wrote:
> >
> > You are missing the point that C does not allow you to
> > dynamically create new functions at runtime.
>
> If that's a requirement, then Haskell doesn't have
> first-class functions either. I think the functional
> programming people might disagree about that.

FP people would no doubt disagree with your implication
that Haskell doesn't allow you to dynamically create
new functions...! Elementary example:

module Main where

compose :: (Integer -> Integer) -> (Integer -> Integer) -> (Integer ->
Integer)
compose f g = f . g

plus1 :: Integer -> Integer
plus1 x = x + 1

times3 :: Integer -> Integer
times3 x = x * 3

main = putStr (show ((compose plus1 times3) 52))

The function that we're applying to argument 52 is
dynamically created at runtime (and returned from
function compose) by composing the functions plus1
and times3. Haskell, of course, also offers several
other ways to dynamically create new functions at
runtime.


Alex


Cameron Laird

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
In article <3A1410C4...@letterror.com>,
Just van Rossum <ju...@letterror.com> wrote:
>Lyle Johnson wrote:
>> I've just started looking at Ruby, mainly because my curiosity got the
>> better of me. So far I'm underwhelmed. I can see how it might appeal to Perl
>> users but not Python users. I'll try to present my finding to the newsgroup
>> after I've had more time to give it a fair shake.

>
>One odd thing I came across: while in Ruby apparently everything is an
>instance (no difference between types and classes) I read somewhere that
>functions and methods are _not_ first class citizens.
>
>Just

A different answer from others I've seen here: this used
to be true, but now they *are* first-class citizens for-
mally (although sort of not in their implementation)
<URL:http://deja.com/=dnc/getdoc.xp?AN=695955107>
--

Cameron Laird <cla...@NeoSoft.com>
Business: http://www.Phaseit.net
Personal: http://starbase.neosoft.com/~claird/home.html

Suchandra Thapa

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
Alex Martelli <ale...@yahoo.com> wrote:
>The "new.function" function (in standard module 'new') lets you
>"runtime-create" function objects in Python (you supply to it a
>code-object, which you can get/create in various ways, as well
>as a global-namespace dict, and, optionally, a name-string and
>a tuple of default values for arguments). Also, 'def' is an
>executable statement: each time it's executed, it returns a NEW
>function-object, too (much like a new.function, but with the
>code-object being the body of the 'def', the name being the
>identifier right after the 'def' keyword, and the global namespace
>being the one currently in use). lambda, in other words, is just
>one of several ways that Python offers to create function objects
>at runtime; its limitations (that the code-object be just an
>expression, not a statement-suite) only affect that specific
>syntax, not other ones.

I was so wrapped up in the lambda mentality that I didn't realize
that there were other ways to dynamically generate functions. Incidentally,
is it possible to do something like a

func_string = 'def foo(x,y): ...'
eval(func_string)

and where func_string is possibly dynamically generated based on a variety
of inputs?

Ben Wolfson

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
In article <slrn91lj4p....@localhost.localdomain>,
Suchandra Thapa <s-t...@uchicago.edu> wrote:

>Alex Martelli <ale...@yahoo.com> wrote:
>>The "new.function" function (in standard module 'new') lets you
>>"runtime-create" function objects in Python (you supply to it a
>>code-object, which you can get/create in various ways, as well
>>as a global-namespace dict, and, optionally, a name-string and
>>a tuple of default values for arguments). Also, 'def' is an
>>executable statement: each time it's executed, it returns a NEW
>>function-object, too (much like a new.function, but with the
>>code-object being the body of the 'def', the name being the
>>identifier right after the 'def' keyword, and the global namespace
>>being the one currently in use). lambda, in other words, is just
>>one of several ways that Python offers to create function objects
>>at runtime; its limitations (that the code-object be just an
>>expression, not a statement-suite) only affect that specific
>>syntax, not other ones.
>
> I was so wrapped up in the lambda mentality that I didn't realize
>that there were other ways to dynamically generate functions. Incidentally,
>is it possible to do something like a
>
>func_string = 'def foo(x,y): ...'
>eval(func_string)
>
>and where func_string is possibly dynamically generated based on a variety
>of inputs?

Yes, and it can be useful, too:

__funcs = []
__results = []
__count = 0
__mapped = {}
__procedure_faker = 'lambda *a, **k: __getresult(%d, a, k)'

def __getresult(key, positional, keyword):
func = __funcs[key]
results = __results[key]
key = '%r%r' % (positional, keyword)#the tuple itself is un-hashable.
if not results.has_key(key):
results[key] = apply(func, positional, keyword)
return results[key]

def memoize(func):
if not alreadymemoized(func):
global __count
rval = eval(__procedure_faker % __count)
__funcs.append(func)
__results.append({})
__mapped[id(func)] = 1
__count += 1
return rval
return func

--
BTR
I'm sure there isn't a single person alive who hasn't mistaken an antimetabole
for a chiasmus before.
-- John Flynn, in apihna

Michel Pelletier

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
Suchandra Thapa wrote:
>
> Alex Martelli <ale...@yahoo.com> wrote:
> >The "new.function" function (in standard module 'new') lets you
> >"runtime-create" function objects in Python (you supply to it a
> >code-object, which you can get/create in various ways, as well
> >as a global-namespace dict, and, optionally, a name-string and
> >a tuple of default values for arguments). Also, 'def' is an
> >executable statement: each time it's executed, it returns a NEW
> >function-object, too (much like a new.function, but with the
> >code-object being the body of the 'def', the name being the
> >identifier right after the 'def' keyword, and the global namespace
> >being the one currently in use). lambda, in other words, is just
> >one of several ways that Python offers to create function objects
> >at runtime; its limitations (that the code-object be just an
> >expression, not a statement-suite) only affect that specific
> >syntax, not other ones.
>
> I was so wrapped up in the lambda mentality that I didn't realize
> that there were other ways to dynamically generate functions. Incidentally,
> is it possible to do something like a
>
> func_string = 'def foo(x,y): ...'
> eval(func_string)
>
> and where func_string is possibly dynamically generated based on a variety
> of inputs?

I just learned this little trick today in fact:

foo = {}
exec "def foo(x): pass" in foo
myfunc = foo['foo']

Now you can call myfunc. It gets really weird when you use "%s"
substitutions in your exec'ed string.

-Michel

Michael Hudson

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
Michel Pelletier <mic...@digicool.com> writes:

> I just learned this little trick today in fact:
>
> foo = {}
> exec "def foo(x): pass" in foo
> myfunc = foo['foo']
>
> Now you can call myfunc. It gets really weird when you use "%s"
> substitutions in your exec'ed string.

I should perhaps give warning that I started down this road slightly
more than two years ago, and ended up at the bytecodehacks...

Cheers,
M.

--
SCSI is not magic. There are fundamental technical reasons why it
is necessary to sacrifice a young goat to your SCSI chain now and
then. -- John Woods

Alex Martelli

unread,
Nov 22, 2000, 3:00:00 AM11/22/00
to
"Suchandra Thapa" <sst...@harper.uchicago.edu> wrote in message
news:slrn91lj4p....@localhost.localdomain...
[snip]

> is it possible to do something like a
>
> func_string = 'def foo(x,y): ...'
> eval(func_string)
>
> and where func_string is possibly dynamically generated based on a variety
> of inputs?

Almost, but you need an exec rather than eval -- the latter
is limited to an expression, and def is a statement, whence
the need for exec (which _does_ do statements:-).


Alex


Greg Ewing

unread,
Nov 22, 2000, 7:15:24 PM11/22/00
to
Alex Martelli wrote:
>
> Haskell, of course, also offers several
> other ways to dynamically create new functions at
> runtime.

Yes, but the poster seemed to be claiming that
you have to be able to do something like Python's
trick of exec-ing code that you make up at run
time, otherwise you don't have first-class
functions!

I think that's a rather more extreme definition
of first-class than most people use.

Suchandra Thapa

unread,
Nov 23, 2000, 3:00:00 AM11/23/00
to
Greg Ewing <gr...@cosc.canterbury.ac.nz> wrote:
>Alex Martelli wrote:
>>
>> Haskell, of course, also offers several
>> other ways to dynamically create new functions at
>> runtime.
>
>Yes, but the poster seemed to be claiming that
>you have to be able to do something like Python's
>trick of exec-ing code that you make up at run
>time, otherwise you don't have first-class
>functions!
>
>I think that's a rather more extreme definition
>of first-class than most people use.

My post just stated that first class functions implied
that functions could be treated like that including generating
them dynamically and that C didn't have first class functions
because it couldn't do this.

0 new messages